package busterminal;

import busterminal.command.ExitCommand;
import busterminal.command.bus.CreateBusCommand;
import busterminal.command.bus.DeleteBusCommand;
import busterminal.command.bus.FindByStateNumberCommand;
import busterminal.command.bus.ReadBusCommand;
import busterminal.command.bus.UpdateBusCommand;
import busterminal.command.bus.ViewBusListCommand;
import busterminal.command.busmodel.CreateBusModelCommand;
import busterminal.command.busmodel.DeleteBusModelCommand;
import busterminal.command.busmodel.FindByModelNameCommand;
import busterminal.command.busmodel.ReadBusModelCommand;
import busterminal.command.busmodel.UpdateBusModelCommand;
import busterminal.command.busmodel.ViewBusModelListCommand;
import busterminal.command.route.CreateRouteCommand;
import busterminal.command.route.DeleteRouteCommand;
import busterminal.command.route.FindByRouteNameCommand;
import busterminal.command.route.FindByStoppingPointName;
import busterminal.command.route.ReadRouteCommand;
import busterminal.command.route.UpdateRouteCommand;
import busterminal.command.route.ViewRouteListCommand;
import busterminal.command.scheduleditem.CreateScheduledItemCommand;
import busterminal.command.scheduleditem.DeleteScheduledItemCommand;
import busterminal.command.scheduleditem.FindScheduledItemByRoutingDaysCommand;
import busterminal.command.scheduleditem.UpdateScheduledItemCommand;
import busterminal.command.scheduleditem.ViewScheduledItemListCommand;
import busterminal.command.stoppingpoint.CreateStoppingPointCommand;
import busterminal.command.stoppingpoint.DeleteStoppingPointCommand;
import busterminal.command.stoppingpoint.FindStoppingPointByNameCommand;
import busterminal.command.stoppingpoint.UpdateStoppingPointCommand;
import busterminal.command.stoppingpoint.ViewStoppingPointListCommand;
import busterminal.command.trip.CreateTripCommand;
import busterminal.command.trip.DeleteTripCommand;
import busterminal.command.trip.FindTripByDateCommand;
import busterminal.command.trip.UpdateTripCommand;
import busterminal.command.trip.ViewTripListCommand;
import busterminal.entity.BusImplementation;
import busterminal.entity.BusModelImplementation;
import busterminal.entity.RouteImplementation;
import busterminal.entity.ScheduledItemImplementation;
import busterminal.entity.StoppingPoint;
import busterminal.entity.StoppingPointImplementation;
import busterminal.entity.TripImplementation;
import busterminal.entity.service.DaysOfWeek;
import busterminal.entity.service.PurposeType;
import busterminal.entity.service.RouteType;
import busterminal.entity.service.Time;
import busterminal.entity.service.TripState;
import busterminal.entity.service.VehicleType;
import busterminal.exception.BusinessException;
import busterminal.menu.Menu;
import busterminal.persistence.BusDAO;
import busterminal.persistence.BusModelDAO;
import busterminal.persistence.DaoFactory;
import busterminal.persistence.RouteDAO;
import busterminal.persistence.ScheduledItemDAO;
import busterminal.persistence.StoppingPointDAO;
import busterminal.persistence.TripDAO;
import busterminal.persistence.jdbc.JdbcDAOFactory;
import busterminal.services.ServiceLocator;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

/**
 * Запускающий класс
 */
public class Application {

    private DaoFactory daoFactory;
    private Menu mainMenu;

    /**
     * Установить значение фабрики
     * @param daoFactory DAO фабрика
     */
    public void setDaoFactory(DaoFactory daoFactory) {
        this.daoFactory = daoFactory;
    }

    /**
     * Инициализация приложения
     */
    public void init() {
        mainMenu = new Menu("Main menu");

        Menu busSubMenu = new Menu("Bus ...");
        Menu busModelSubMenu = new Menu("Bus model ...");
        Menu routeSubMenu = new Menu("Route ...");
        Menu scheduledItemSubMenu = new Menu("Scheduled item ...");
        Menu stoppingPointSubMenu = new Menu("Stopping point ...");
        Menu tripSubMenu = new Menu("Trip ...");

        mainMenu.addCommand(busSubMenu);
        mainMenu.addCommand(busModelSubMenu);
        mainMenu.addCommand(routeSubMenu);
        mainMenu.addCommand(scheduledItemSubMenu);
        mainMenu.addCommand(stoppingPointSubMenu);
        mainMenu.addCommand(tripSubMenu);
        mainMenu.addCommand(new ExitCommand());

        //Bus
        busSubMenu.addCommand(new CreateBusCommand());
        busSubMenu.addCommand(new ReadBusCommand());
        busSubMenu.addCommand(new UpdateBusCommand());
        busSubMenu.addCommand(new DeleteBusCommand());
        busSubMenu.addCommand(new ViewBusListCommand());
        busSubMenu.addCommand(new FindByStateNumberCommand());

        //Bus model
        busModelSubMenu.addCommand(new CreateBusModelCommand());
        busModelSubMenu.addCommand(new ReadBusModelCommand());
        busModelSubMenu.addCommand(new UpdateBusModelCommand());
        busModelSubMenu.addCommand(new DeleteBusModelCommand());
        busModelSubMenu.addCommand(new ViewBusModelListCommand());
        busModelSubMenu.addCommand(new FindByModelNameCommand());

        //Route
        routeSubMenu.addCommand(new CreateRouteCommand());
        routeSubMenu.addCommand(new ReadRouteCommand());
        routeSubMenu.addCommand(new UpdateRouteCommand());
        routeSubMenu.addCommand(new DeleteRouteCommand());
        routeSubMenu.addCommand(new ViewRouteListCommand());
        routeSubMenu.addCommand(new FindByRouteNameCommand());
        routeSubMenu.addCommand(new FindByStoppingPointName());        

        //Scheduled item
        scheduledItemSubMenu.addCommand(new CreateScheduledItemCommand());
        scheduledItemSubMenu.addCommand(new DeleteScheduledItemCommand());
        scheduledItemSubMenu.addCommand(new FindScheduledItemByRoutingDaysCommand());
        scheduledItemSubMenu.addCommand(new UpdateScheduledItemCommand());
        scheduledItemSubMenu.addCommand(new ViewScheduledItemListCommand());

        //Stopping point
        stoppingPointSubMenu.addCommand(new CreateStoppingPointCommand());
        stoppingPointSubMenu.addCommand(new DeleteStoppingPointCommand());
        stoppingPointSubMenu.addCommand(new FindStoppingPointByNameCommand());
        stoppingPointSubMenu.addCommand(new UpdateStoppingPointCommand());
        stoppingPointSubMenu.addCommand(new ViewStoppingPointListCommand());

        //Trip
        tripSubMenu.addCommand(new CreateTripCommand());
        tripSubMenu.addCommand(new DeleteTripCommand());
        tripSubMenu.addCommand(new FindTripByDateCommand());
        tripSubMenu.addCommand(new UpdateTripCommand());
        tripSubMenu.addCommand(new ViewTripListCommand());

        ServiceLocator.registerService(BusDAO.class, daoFactory.getBusDAO());
        ServiceLocator.registerService(BusModelDAO.class, daoFactory.getBusModelDAO());
        ServiceLocator.registerService(RouteDAO.class, daoFactory.getRouteDAO());
        ServiceLocator.registerService(ScheduledItemDAO.class, daoFactory.getScheduledItemDAO());
        ServiceLocator.registerService(StoppingPointDAO.class, daoFactory.getStoppingPointDAO());
        ServiceLocator.registerService(TripDAO.class, daoFactory.getTripDAO());
    }

    /**
     * Запускающий метод
     * @param args параметры командной строки (не используются в приложении)
     */
    public static void main(String args[]) {
        Application app = new Application();
        //app.setDaoFactory(new MemoryDAOFactory());
        app.setDaoFactory(new JdbcDAOFactory());
        app.init();
        //app.fillTestData();
        app.start();
    }

    /**
     * Вывод меню на экран
     */
    public void start() {
        while (true) {
            mainMenu.execute();
        }
    }

    /**
     * Ввести тестовые данные
     */
    private void fillTestData() {
        BusDAO busDAO = daoFactory.getBusDAO();
        BusModelDAO busModelDAO = daoFactory.getBusModelDAO();
        RouteDAO routeDAO = daoFactory.getRouteDAO();
        ScheduledItemDAO scheduledItemDAO = daoFactory.getScheduledItemDAO();
        StoppingPointDAO stoppingPointDAO = daoFactory.getStoppingPointDAO();
        TripDAO tripDAO = daoFactory.getTripDAO();

        //Stopping point
        stoppingPointDAO.create(new StoppingPointImplementation("Brest"));
        stoppingPointDAO.create(new StoppingPointImplementation("Gomel"));
        stoppingPointDAO.create(new StoppingPointImplementation("Grodno"));
        stoppingPointDAO.create(new StoppingPointImplementation("Vitebsk"));
        stoppingPointDAO.create(new StoppingPointImplementation("Minsk"));
        stoppingPointDAO.create(new StoppingPointImplementation("Mogilev"));

        //Bus model
        busModelDAO.create(new BusModelImplementation("MAZ-103", VehicleType.BUS));
        busModelDAO.create(new BusModelImplementation("PAZ-4233", VehicleType.BUS));
        busModelDAO.create(new BusModelImplementation("RAPH-2203", VehicleType.MINIBUS));
        busModelDAO.create(new BusModelImplementation("Fiat Ducato", VehicleType.MINIBUS));
        busModelDAO.create(new BusModelImplementation("NEMAN", VehicleType.BUS));

        //Bus
        busDAO.create(new BusImplementation("АА 0014-3", busModelDAO.read(1), 1998, PurposeType.MOTOR_COACH));
        busDAO.create(new BusImplementation("АА 9381-3", busModelDAO.read(2), 2005, PurposeType.MOTOR_COACH));
        busDAO.create(new BusImplementation("ЕВ 2529", busModelDAO.read(4), 2012, PurposeType.CUSTOM_BUS));
        busDAO.create(new BusImplementation("АВ 6945-3", busModelDAO.read(5), 2009, PurposeType.MOTOR_COACH));

        //Route
        ArrayList<StoppingPoint> intermediateStoppingPoints = new ArrayList<StoppingPoint>();
        intermediateStoppingPoints.add(stoppingPointDAO.read(3));
        intermediateStoppingPoints.add(stoppingPointDAO.read(5));
        intermediateStoppingPoints.add(stoppingPointDAO.read(6));
        routeDAO.create(new RouteImplementation("316", "Vitebsk-Brest", stoppingPointDAO.read(4), stoppingPointDAO.read(1), intermediateStoppingPoints, RouteType.INTERCITY_ROUTE));
        intermediateStoppingPoints.clear();
        intermediateStoppingPoints.add(stoppingPointDAO.read(5));
        routeDAO.create(new RouteImplementation("256", "Vitebsk-Mogilev", stoppingPointDAO.read(4), stoppingPointDAO.read(6), intermediateStoppingPoints, RouteType.INTERCITY_ROUTE));
        intermediateStoppingPoints.clear();
        intermediateStoppingPoints.add(stoppingPointDAO.read(6));
        routeDAO.create(new RouteImplementation("256", "Vitebsk-Gomel", stoppingPointDAO.read(4), stoppingPointDAO.read(2), intermediateStoppingPoints, RouteType.INTERCITY_ROUTE));

        //Scheduled item
        try {
            List<DaysOfWeek> routingDays = new ArrayList<DaysOfWeek>();
            routingDays.add(DaysOfWeek.MONDAY);
            routingDays.add(DaysOfWeek.WEDNESDAY);
            routingDays.add(DaysOfWeek.FRIDAY);
            scheduledItemDAO.create(new ScheduledItemImplementation(routeDAO.read(1), Time.parseTime("01:00"), Time.parseTime("12:00"), Time.parseTime("12:05"), Time.parseTime("23:50"), routingDays, (byte) 1));
            routingDays = new ArrayList<DaysOfWeek>();
            routingDays.add(DaysOfWeek.TUESDAY);
            routingDays.add(DaysOfWeek.THURSDAY);
            scheduledItemDAO.create(new ScheduledItemImplementation(routeDAO.read(2), Time.parseTime("05:00"), Time.parseTime("13:00"), Time.parseTime("14:00"), Time.parseTime("23:00"), routingDays, (byte) 2));
            routingDays = new ArrayList<DaysOfWeek>();
            routingDays.add(DaysOfWeek.MONDAY);
            routingDays.add(DaysOfWeek.THURSDAY);
            routingDays.add(DaysOfWeek.SUNDAY);
            scheduledItemDAO.create(new ScheduledItemImplementation(routeDAO.read(3), Time.parseTime("06:00"), Time.parseTime("14:00"), Time.parseTime("14:10"), Time.parseTime("23:40"), routingDays, (byte) 3));
        } catch (BusinessException e) {
            System.err.println("Error in test data: " + e.getMessage());
        }

        //Trip
        try {
            tripDAO.create(new TripImplementation(routeDAO.read(1), TripState.FINISHED, "24.07.2012", busDAO.read(1), "Ivanov I.I.", "Petrov P.P."));
            tripDAO.create(new TripImplementation(routeDAO.read(2), TripState.PLANNED, "25.07.2012", busDAO.read(2), "Ivanov I.I.", "Sergeev S.S."));
        } catch (ParseException e) {
            System.err.println("Error in test data: " + e.getMessage());
        }
    }
}
